home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / util / arc / xadmaster.lha / xad / Developer / Sources / tools / xadUnFile.c < prev   
Encoding:
C/C++ Source or Header  |  2000-08-31  |  29.3 KB  |  983 lines

  1. #ifdef MULTIFILE
  2.   #define NAME         "xadUnFileM"
  3. #else
  4.   #define NAME         "xadUnFile"
  5. #endif
  6. #define DISTRIBUTION "(Freeware) "
  7. #define REVISION     "20"
  8. #define DATE         "27.07.2000"
  9.  
  10. /* Programmheader
  11.  
  12.     Name:        xadUnFile
  13.     Author:        SDI
  14.     Distribution:    Freeware
  15.     Description:    dearchives file archives
  16.     Compileropts:    -
  17.     Linkeropts:    -gsi -l amiga
  18.  
  19.  1.0   13.09.98 : first version
  20.  1.1   18.11.98 : added FILE parameter and directory creation
  21.  1.2   03.02.99 : added corrupt message
  22.  1.3   07.02.99 : added missing "group crunched" handling
  23.  1.4   16.03.99 : errors no longer abort decrunching
  24.  1.5   21.06.99 : added support for multiple input files and renaming
  25.  1.6   04.07.99 : bug fix
  26.  1.7   18.07.99 : added SHOWPROT, reduced status prints, added QUIT,
  27.     splitted in xadUnFile and xadUnFileM
  28.  1.8   19.08.99 : also strips "/" at name start for NOABS
  29.  1.9   15.09.99 : forgot to set date/comment/bits for directories
  30.  1.10  28.09.99 : added NAMESIZE keyword
  31.  1.11  01.11.99 : added SFS keyword
  32.  1.12  07.12.99 : added NOKILLPART keyword
  33.  1.13  17.12.99 : added VERBOSE mode
  34.  1.14  14.01.00 : added DARC, ENTRY, DIMG
  35.  1.15  12.02.00 : added auto DIMG and pattern support
  36.  1.16  05.03.00 : bug fixes
  37.  1.17  19.03.00 : support for XADFIF_NOUNCRUNCHSIZE
  38.  1.18  28.05.00 : added final report
  39.  1.19  04.06.00 : added multi-filesystem support
  40.  1.20  27.07.00 : fixed multi-filesystem support for empty fs parts
  41. */
  42.  
  43. #include <proto/xadmaster.h>
  44. #include <proto/exec.h>
  45. #include <proto/dos.h>
  46. #include <exec/memory.h>
  47. #include <dos/dosasl.h>
  48. #include <utility/hooks.h>
  49. #include "SDI_version.h"
  50. #include "SDI_compiler.h"
  51. #define SDI_TO_ANSI
  52. #include "SDI_ASM_STD_protos.h"
  53.  
  54. struct xadMasterBase *    xadMasterBase = 0;
  55. struct DosLibrary *     DOSBase = 0;
  56. struct ExecBase *     SysBase  = 0;
  57.  
  58. #define MINPRINTSIZE    51200    /* 50KB */
  59. #define NAMEBUFSIZE    512
  60. #define PATBUFSIZE    (NAMEBUFSIZE*2+10)
  61.  
  62. #ifdef MULTIFILE
  63. #define PARAM    "FROM/A/M,DEST=DESTDIR/K,PASSWORD/K,FILE/K,"    \
  64.         "NAMESIZE/K/N,FFS=OFS/S,SFS/S,"            \
  65.         "INFO=LIST/S,Q=QUIET/S,AM=ASKMAKEDIR/S,"    \
  66.         "OW=OVERWRITE/S,SP=SHOWPROT/S,VERBOSE/S,"    \
  67.         "DARC=DISKARCHIVE/S,ENTRY/K/N,DIMG=DISKIMAGE/S,"\
  68.         "NA=NOABS/S,NC=NOCOMMENT/S,ND=NODATE/S,"    \
  69.         "NE=NOEXTERN/S,NKP=NOKILLPART/S,NP=NOPROT/S,"    \
  70.         "NT=NOTREE/S"
  71. #else
  72. #define PARAM    "FROM/A,DEST=DESTDIR,PASSWORD/K,FILE/M,"    \
  73.         "NAMESIZE/K/N,FFS=OFS/S,SFS/S,"            \
  74.         "INFO=LIST/S,Q=QUIET/S,AM=ASKMAKEDIR/S,"    \
  75.         "OW=OVERWRITE/S,SP=SHOWPROT/S,VERBOSE/S,"    \
  76.         "DARC=DISKARCHIVE/S,ENTRY/K/N,DIMG=DISKIMAGE/S,"\
  77.         "NA=NOABS/S,NC=NOCOMMENT/S,ND=NODATE/S,"    \
  78.         "NE=NOEXTERN/S,NKP=NOKILLPART/S,NP=NOPROT/S,"    \
  79.         "NT=NOTREE/S"
  80. #endif
  81.  
  82. #ifdef MULTIFILE
  83. #define OPTIONS1 \
  84.   "FROM       The input archive file(s) (no patterns allowed)\n"    \
  85.   "DESTDIR    The destination directory, not needed with INFO\n"    \
  86.   "PASSWORD   A password for encrypted archives\n"            \
  87.   "FILE       Filename (with patterns) to be extracted\n"
  88. #else
  89. #define OPTIONS1 \
  90.   "FROM       The input archive file (no patterns allowed)\n"        \
  91.   "DESTDIR    The destination directory, not needed with INFO\n"    \
  92.   "PASSWORD   A password for encrypted archives\n"            \
  93.   "FILE       Filename(s) (with patterns) to be extracted\n"
  94. #endif
  95.  
  96. #define OPTIONS2 \
  97.   "NAMESIZE   Names with more characters result in rename request\n"    \
  98.   "FFS=OFS    Sets NAMESIZE to 30\n"                    \
  99.   "SFS        Sets NAMESIZE to 100\n"                    \
  100.   "INFO       Shows archive information without extracting\n"        \
  101.   "QUIET      Turns of progress report and user interaction\n"        \
  102.   "ASKMAKEDIR You get asked before a directory is created\n"        \
  103.   "OVERWRITE  Files are overwritten without asking\n"            \
  104.   "SHOWPROT   Show protection information with LIST\n"            \
  105.   "VERBOSE    Print some more information with INFO\n"            \
  106.   "DARC       input file is an disk archive\n"                \
  107.   "ENTRY      entry number for DARC, if not the first one\n"        \
  108.   "DIMG          input file is an disk image (ADF file)\n"            \
  109.   "NOABS      Do not extract absolute path name parts\n"        \
  110.   "NOCOMMENT  No filenote comments are extracted or displayed\n"    \
  111.   "NODATE     Creation date information gets not extracted\n"        \
  112.   "NOEXTERN   Turns off usage of external clients\n"            \
  113.   "NOKILLPART Do not delete partial or corrupt output files.\n"        \
  114.   "NOPROT     Protection information gets not extracted\n"        \
  115.   "NOTREE     Files are extracted without subdirectories\n"
  116.  
  117. struct xHookArgs {
  118.   STRPTR name;
  119.   ULONG flags;
  120.   ULONG finish;
  121.   ULONG lastprint;
  122. };
  123.  
  124. struct Args {
  125. #ifdef MULTIFILE
  126.   STRPTR * from;
  127.   STRPTR   destdir;
  128.   STRPTR   password;
  129.   STRPTR   file;
  130. #else
  131.   STRPTR   from;
  132.   STRPTR   destdir;
  133.   STRPTR   password;
  134.   STRPTR * file;
  135. #endif
  136.   LONG *   namesize;
  137.   ULONG    ffs;
  138.   ULONG       sfs;
  139.   ULONG    info;
  140.   ULONG    quiet;
  141.   ULONG    askmakedir;
  142.   ULONG    overwrite;
  143.   ULONG       showprot;
  144.   ULONG    verbose;
  145.   ULONG    diskarchive;
  146.   LONG *   entry;
  147.   ULONG    diskimage;
  148.   ULONG    noabs;
  149.   ULONG    nocomment;
  150.   ULONG    nodate;
  151.   ULONG    noextern;
  152.   ULONG       nokillpart;
  153.   ULONG    noprot;
  154.   ULONG    notree;
  155. };
  156.  
  157. ASM(ULONG) progrhook(REG(a0, struct Hook *),
  158.   REG(a1, struct xadProgressInfo *));
  159.  
  160. void ShowProt(ULONG i);
  161. LONG CheckNameSize(STRPTR name, ULONG size);
  162. void CalcPercent(ULONG cr, ULONG ucr, ULONG *p1, ULONG *p2);
  163.  
  164. #ifndef MULTIFILE
  165.   LONG CheckName(STRPTR *pat, STRPTR name);
  166. #else
  167.   STRPTR *GetNames(STRPTR *names);
  168. #endif
  169.  
  170. ULONG start(void)
  171. {
  172.   ULONG ret = RETURN_FAIL;
  173.   struct DosLibrary *dosbase;
  174.  
  175.   SysBase = (*((struct ExecBase **) 4));
  176.   { /* test for WB and reply startup-message */
  177.     struct Process *task;
  178.     if(!(task = (struct Process *) FindTask(0))->pr_CLI)
  179.     {
  180.       WaitPort(&task->pr_MsgPort);
  181.       Forbid();
  182.       ReplyMsg(GetMsg(&task->pr_MsgPort));
  183.       return RETURN_FAIL;
  184.     }
  185.   }
  186.  
  187.   if((dosbase = (struct DosLibrary *) OpenLibrary("dos.library", 37)))
  188.   {
  189.     LONG err = 0;
  190.     struct xadMasterBase *xadmasterbase;
  191.  
  192.     DOSBase = dosbase;
  193.     if((xadmasterbase = (struct xadMasterBase *)
  194.     OpenLibrary("xadmaster.library", 7)))
  195.     {
  196.       struct Args args;
  197.       struct RDArgs *rda;
  198.       
  199.       memset(&args, 0, sizeof(struct Args));
  200.       xadMasterBase = xadmasterbase;
  201.  
  202.       if((rda = (struct RDArgs *) AllocDosObject(DOS_RDARGS, 0)))
  203.       {
  204.         rda->RDA_ExtHelp = OPTIONS1 OPTIONS2;
  205.  
  206.         if(ReadArgs(PARAM, (LONG *) &args, rda))
  207.         {
  208.           LONG namesize = 0;
  209.  
  210. #ifdef MULTIFILE
  211.       STRPTR *argstring;
  212. #endif
  213.           
  214.           if(args.namesize && *args.namesize > 0)
  215.             namesize = *args.namesize;
  216.           else if(args.ffs)
  217.             namesize = 30;
  218.           else if(args.sfs)
  219.             namesize = 100;
  220.  
  221. #ifdef MULTIFILE
  222.       if(!(args.from = argstring = GetNames(args.from))) /* correct the argument list */
  223.             ;
  224.           else if(!(*argstring))
  225.             SetIoErr(ERROR_REQUIRED_ARG_MISSING);
  226.       else /* comes together with following if! */
  227. #endif
  228.       if(args.destdir || args.info)
  229.       {
  230.             ULONG numfile = 0, numdir = 0, numerr = 0;
  231.         struct xadArchiveInfo *ai;
  232.             struct TagItem ti[5];
  233.             struct TagItem ti2[4];
  234.             LONG loop = 2;
  235.             
  236.             ti[1].ti_Tag = XAD_NOEXTERN;
  237.         ti[1].ti_Data = args.noextern;
  238.         ti[2].ti_Tag = args.password ? XAD_PASSWORD : TAG_IGNORE;
  239.         ti[2].ti_Data = (ULONG) args.password;
  240.         ti[3].ti_Tag = args.entry ? XAD_ENTRYNUMBER : TAG_IGNORE;
  241.         ti[3].ti_Data = args.entry ? *args.entry : 1;
  242.         ti[4].ti_Tag = TAG_DONE;
  243.  
  244.         ti2[1].ti_Tag = XAD_NOEMPTYERROR;
  245.         ti2[1].ti_Data = TRUE;
  246.         ti2[2].ti_Tag = TAG_DONE;
  247.         ti2[3].ti_Tag = TAG_DONE; /* needed later for loop */
  248.  
  249.         if((ai = (struct xadArchiveInfo *)
  250.         xadAllocObjectA(XADOBJ_ARCHIVEINFO, 0)))
  251.         {
  252. #ifdef MULTIFILE
  253.           if(*(args.from+1))
  254.           {
  255.             struct xadSplitFile *sf = 0, *sf2, *sf0 = 0;
  256.         while(*args.from && !err)
  257.         {
  258.           if((sf2 = xadAllocObjectA(XADOBJ_SPLITFILE, 0)))
  259.           {
  260.             if(sf)
  261.             {
  262.               sf->xsf_Next = sf2; sf = sf2;
  263.             }
  264.             else
  265.               sf0 = sf = sf2;
  266.             sf->xsf_Type = XAD_INFILENAME;
  267.             sf->xsf_Data = (ULONG) *(args.from++);
  268.           }
  269.           else
  270.             err = XADERR_NOMEMORY;
  271.         }
  272.             if(!err)
  273.             {
  274.               if(args.diskarchive)
  275.               {
  276.                 ti[0].ti_Tag = XAD_INSPLITTED;
  277.                 ti[0].ti_Data = (ULONG) sf0;
  278.  
  279.             ti2[0].ti_Tag = XAD_INDISKARCHIVE;
  280.             ti2[0].ti_Data = (ULONG) ti;
  281.                 if((err = xadGetDiskInfoA(ai, ti2)))
  282.                 {
  283.                   ti2[0].ti_Tag = XAD_INSPLITTED;
  284.                   ti2[0].ti_Data = (ULONG) sf0;
  285.                   if(!xadGetDiskInfoA(ai, ti2))
  286.                     err = 0;
  287.                 }
  288.               }
  289.               else if(args.diskimage)
  290.               {
  291.                 ti2[0].ti_Tag = XAD_INSPLITTED;
  292.                 ti2[0].ti_Data = (ULONG) sf0;
  293.                 err = xadGetDiskInfoA(ai, ti2);
  294.               }
  295.               else
  296.               {
  297.                 err = xadGetInfo(ai, XAD_INSPLITTED, sf0, XAD_NOEXTERN,
  298.                 args.noextern, args.password ? XAD_PASSWORD : TAG_IGNORE,
  299.                 args.password, TAG_DONE);
  300.                 --loop;
  301.               }
  302.             }
  303.             while(sf0)
  304.             {
  305.               sf2 = sf0; sf0 = sf0->xsf_Next;
  306.               xadFreeObjectA(sf2, 0);
  307.             }
  308.           }
  309.           else if(args.diskarchive)
  310.           {
  311.             ti[0].ti_Tag = XAD_INFILENAME;
  312.             ti[0].ti_Data = (ULONG) *args.from;
  313.  
  314.         ti2[0].ti_Tag = XAD_INDISKARCHIVE;
  315.         ti2[0].ti_Data = (ULONG) ti;
  316.             if((err = xadGetDiskInfoA(ai, ti2)))
  317.             {
  318.               ti2[0].ti_Tag = XAD_INFILENAME;
  319.               ti2[0].ti_Data = (ULONG) *args.from;
  320.               if(!xadGetDiskInfoA(ai, ti2))
  321.                 err = 0;
  322.             }
  323.           }
  324.           else if(args.diskimage)
  325.           {
  326.             ti2[0].ti_Tag = XAD_INFILENAME;
  327.             ti2[0].ti_Data = (ULONG) *args.from;
  328.             err = xadGetDiskInfoA(ai, ti2);
  329.           }
  330.           else
  331.           {
  332.             err = xadGetInfo(ai, XAD_INFILENAME, *args.from,
  333.             XAD_NOEXTERN, args.noextern, args.password ? XAD_PASSWORD :
  334.             TAG_IGNORE, args.password, TAG_DONE);
  335.             --loop;
  336.           }
  337. #else
  338.           if(args.diskarchive)
  339.           { 
  340.             ti[0].ti_Tag = XAD_INFILENAME;
  341.             ti[0].ti_Data = (ULONG) args.from;
  342.  
  343.         ti2[0].ti_Tag = XAD_INDISKARCHIVE;
  344.         ti2[0].ti_Data = (ULONG) ti;
  345.             if((err = xadGetDiskInfoA(ai, ti2)))
  346.             {
  347.               ti2[0].ti_Tag = XAD_INFILENAME;
  348.               ti2[0].ti_Data = (ULONG) args.from;
  349.               if(!xadGetDiskInfoA(ai, ti2))
  350.                 err = 0;
  351.             }
  352.           }
  353.           else if(args.diskimage)
  354.           {
  355.             ti2[0].ti_Tag = XAD_INFILENAME;
  356.             ti2[0].ti_Data = (ULONG) args.from;
  357.             err = xadGetDiskInfoA(ai, ti2);
  358.           }
  359.           else
  360.           {
  361.             err = xadGetInfo(ai, XAD_INFILENAME, args.from,
  362.             XAD_NOEXTERN, args.noextern, args.password ? XAD_PASSWORD :
  363.             TAG_IGNORE, args.password, TAG_DONE);
  364.             --loop;
  365.           }
  366. #endif
  367.  
  368.           while(!err && loop)
  369.           {
  370.             if(ai->xai_Flags & XADAIF_FILECORRUPT)
  371.               Printf("!!! The archive file has some corrupt data. !!!\n");
  372.             if(args.info)
  373.             {
  374.               struct xadFileInfo *xfi;
  375.               ULONG grsize = 0;
  376.               if(ai->xai_Client)
  377.                 Printf("ClientName: %s\n", ai->xai_Client->xc_ArchiverName);
  378.           Printf("Size     CrndSize Ratio Date       Time     %s%sName\n",
  379.           args.verbose ? "Info           " : "",args.showprot ? "Protection       " : "");
  380.  
  381.               xfi = ai->xai_FileInfo;
  382.               while(xfi && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
  383.               {
  384.                 if(!(xfi->xfi_Flags & XADFIF_GROUPED))
  385.                   grsize = 0;
  386.             if(xfi->xfi_Flags & XADFIF_DIRECTORY)
  387.             {
  388.                   Printf("   <dir>    <dir>       %02ld.%02ld.%04ld %02ld:%02ld:%02ld ",
  389.                   xfi->xfi_Date.xd_Day, xfi->xfi_Date.xd_Month,
  390.                   xfi->xfi_Date.xd_Year, xfi->xfi_Date.xd_Hour,
  391.                   xfi->xfi_Date.xd_Minute, xfi->xfi_Date.xd_Second);
  392.               if(args.verbose)
  393.                 Printf("%-15s", xfi->xfi_EntryInfo);
  394.                   if(args.showprot)
  395.                     ShowProt(xfi->xfi_Protection);
  396.                   Printf("%s\n", args.notree ? FilePart(xfi->xfi_FileName) :
  397.                   xfi->xfi_FileName);
  398.                 }
  399.             else if(xfi->xfi_Flags & XADFIF_GROUPED)
  400.             {
  401.                   Printf("%8ld   merged  n/a  %02ld.%02ld.%04ld %02ld:%02ld:%02ld ",
  402.                   xfi->xfi_Size, xfi->xfi_Date.xd_Day, xfi->xfi_Date.xd_Month,
  403.                   xfi->xfi_Date.xd_Year, xfi->xfi_Date.xd_Hour,
  404.                   xfi->xfi_Date.xd_Minute, xfi->xfi_Date.xd_Second);
  405.               if(args.verbose)
  406.                 Printf("%-15s", xfi->xfi_EntryInfo);
  407.                   if(args.showprot)
  408.                     ShowProt(xfi->xfi_Protection);
  409.                   Printf("%s\n", args.notree ? FilePart(xfi->xfi_FileName) :
  410.                   xfi->xfi_FileName);
  411.                   grsize += xfi->xfi_Size;
  412.                   if(xfi->xfi_Flags & XADFIF_ENDOFGROUP)
  413.                   {
  414.                 ULONG i, j;
  415.               
  416.             CalcPercent(xfi->xfi_GroupCrSize, grsize, &i, &j);
  417.                     Printf("%8ld %8ld %2ld.%1ld%%\n", grsize, xfi->xfi_GroupCrSize, i, j);
  418.                     grsize = 0;
  419.                   }
  420.             }
  421.             else if(xfi->xfi_Flags & XADFIF_NOUNCRUNCHSIZE)
  422.             {
  423.                   Printf("<nosize> %8ld       %02ld.%02ld.%04ld %02ld:%02ld:%02ld ",
  424.                   xfi->xfi_CrunchSize, xfi->xfi_Date.xd_Day, xfi->xfi_Date.xd_Month,
  425.                   xfi->xfi_Date.xd_Year, xfi->xfi_Date.xd_Hour,
  426.                   xfi->xfi_Date.xd_Minute, xfi->xfi_Date.xd_Second);
  427.               if(args.verbose)
  428.                 Printf("%-15s", xfi->xfi_EntryInfo);
  429.                   if(args.showprot)
  430.                     ShowProt(xfi->xfi_Protection);
  431.                   Printf("%s\n", args.notree ? FilePart(xfi->xfi_FileName) :
  432.                   xfi->xfi_FileName);
  433.                 }
  434.             else
  435.             {
  436.               ULONG i, j;
  437.               
  438.               CalcPercent(xfi->xfi_CrunchSize, xfi->xfi_Size, &i, &j);
  439.                   Printf("%8ld %8ld %2ld.%1ld%% %02ld.%02ld.%04ld %02ld:%02ld:%02ld ",
  440.                   xfi->xfi_Size, xfi->xfi_CrunchSize, i, j,
  441.                   xfi->xfi_Date.xd_Day, xfi->xfi_Date.xd_Month,
  442.                   xfi->xfi_Date.xd_Year, xfi->xfi_Date.xd_Hour,
  443.                   xfi->xfi_Date.xd_Minute, xfi->xfi_Date.xd_Second);
  444.               if(args.verbose)
  445.                 Printf("%-15s", xfi->xfi_EntryInfo);
  446.                   if(args.showprot)
  447.                     ShowProt(xfi->xfi_Protection);
  448.                   Printf("%s\n", args.notree ? FilePart(xfi->xfi_FileName) :
  449.                   xfi->xfi_FileName);
  450.                 }
  451.                 if(xfi->xfi_Flags & XADFIF_LINK)
  452.                   Printf("link: %s\n", xfi->xfi_LinkName);
  453.                 if(xfi->xfi_Comment && !args.nocomment)
  454.                   Printf(": %s\n", xfi->xfi_Comment);
  455. #ifdef DEBUG
  456.             if(xfi->xfi_Flags)
  457.             {
  458.                   Printf("Flags: ");
  459.                   if(xfi->xfi_Flags & XADFIF_CRYPTED)
  460.                     Printf("XADFIF_CRYPTED ");
  461.                   if(xfi->xfi_Flags & XADFIF_DIRECTORY)
  462.                     Printf("XADFIF_DIRECTORY ");
  463.                   if(xfi->xfi_Flags & XADFIF_LINK)
  464.                     Printf("XADFIF_LINK ");
  465.                   if(xfi->xfi_Flags & XADFIF_INFOTEXT)
  466.                     Printf("XADFIF_INFOTEXT ");
  467.                   if(xfi->xfi_Flags & XADFIF_GROUPED)
  468.                     Printf("XADFIF_GROUPED ");
  469.                   if(xfi->xfi_Flags & XADFIF_ENDOFGROUP)
  470.                     Printf("XADFIF_ENDOFGROUP ");
  471.                   if(xfi->xfi_Flags & XADFIF_NODATE)
  472.                     Printf("XADFIF_NODATE ");
  473.                   Printf("\n");
  474.                 }
  475. #endif
  476.                 if(xfi->xfi_Flags & XADFIF_CRYPTED)
  477.                   Printf("The entry is encrypted.\n");
  478.                 if(xfi->xfi_Flags & XADFIF_PARTIALFILE)
  479.                   Printf("The entry is no complete file.\n");
  480.                 xfi = xfi->xfi_Next;
  481.               }
  482.               ret = 0;
  483.             }
  484.             else
  485.             {
  486.           struct Hook prhook;
  487.           struct xadFileInfo *fi;
  488.           UBYTE filename[NAMEBUFSIZE];
  489. #ifdef MULTIFILE
  490.             UBYTE parsebuf[PATBUFSIZE];
  491. #endif
  492.           struct xHookArgs xh;
  493.         
  494.           ret = 0;
  495.           xh.name = filename;
  496.           xh.flags = xh.finish = xh.lastprint = 0;
  497.  
  498.           /* Note! The hook may change the filename!!! */
  499.  
  500.               memset(&prhook, 0, sizeof(struct Hook));
  501.               prhook.h_Entry = (ULONG (*)()) progrhook;
  502.               prhook.h_Data = &xh;
  503.           fi = ai->xai_FileInfo;
  504.  
  505. #ifdef MULTIFILE
  506.             if(!args.file || ParsePatternNoCase(args.file, parsebuf, PATBUFSIZE) >= 0)
  507. #endif
  508.             {
  509.             while(fi && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C) && !xh.finish)
  510.             {
  511. #ifdef MULTIFILE
  512.               if(!args.file || MatchPatternNoCase(parsebuf, args.notree ?
  513.               FilePart(fi->xfi_FileName) : fi->xfi_FileName))
  514. #else
  515.               if(!args.file || CheckName(args.file, args.notree ?
  516.               FilePart(fi->xfi_FileName) : fi->xfi_FileName))
  517. #endif
  518.               {
  519.                 CopyMem(args.destdir, filename, strlen(args.destdir)+1);
  520.             if(stricmp(args.destdir, "NIL:"))
  521.             {
  522.                   if(args.notree)
  523.                     AddPart(filename, FilePart(fi->xfi_FileName), NAMEBUFSIZE);
  524.                   else if(!args.noabs)
  525.                     AddPart(filename, fi->xfi_FileName, NAMEBUFSIZE);
  526.                   else
  527.                   {
  528.                     STRPTR fname = filename, f;
  529.  
  530.                 if(*args.destdir)
  531.                 {
  532.                       fname += strlen(args.destdir)-1;
  533.                       if(*fname != ':' && *fname != '/')
  534.                         *(++fname) = '/';
  535.                       ++fname;
  536.                     }
  537.                 for(f = fi->xfi_FileName; *f == '/' || *f == ':'; ++f)
  538.                   ;
  539.                     for(; *f; ++f)
  540.                       *(fname++) = *f == ':' ? '/' : *f;
  541.                     *fname = 0;
  542.                   }
  543.                 }
  544.                 if(fi->xfi_Flags & XADFIF_LINK)
  545.                 {
  546.                   if(!args.quiet)
  547.                     Printf("Skipped Link\n");
  548.                 }
  549.                 else if(fi->xfi_Flags & XADFIF_DIRECTORY)
  550.                 {
  551.                   if(!args.notree)
  552.                   {
  553.                     BPTR a;
  554.                     LONG err = 0, i = 0;
  555.                     UBYTE r;
  556.                 ++numdir;
  557.                     while(filename[i] && !err)
  558.                     {
  559.                         for(;filename[i] && filename[i] != '/'; ++i)
  560.                         ;
  561.                         r = filename[i];
  562.                         filename[i] = 0;
  563.                   if((a = Lock(filename, SHARED_LOCK)))
  564.                           UnLock(a);
  565.                       else if((a = CreateDir(filename)))
  566.                             UnLock(a);
  567.                         else
  568.                             err = 1;
  569.                           filename[i++] = r;
  570.                     }
  571.                     if(!args.quiet)
  572.                     {
  573.                       if(err)
  574.                       {
  575.                         Printf("failed to create directory '%s'\n", fi->xfi_FileName);
  576.                         ++numerr;
  577.                       }
  578.                       else
  579.                         Printf("Created directory   : %s\n", filename);
  580.                     }
  581.                         if(!err)
  582.                         {
  583.                       struct DateStamp d;
  584.  
  585.                           if(!args.nodate && !(fi->xfi_Flags & XADFIF_NODATE)
  586.                           && !xadConvertDates(XAD_DATEXADDATE, &fi->xfi_Date,
  587.                           XAD_GETDATEDATESTAMP, &d, TAG_DONE))
  588.                             SetFileDate(filename, &d);
  589.                           if(!args.noprot)
  590.                             SetProtection(filename, fi->xfi_Protection);
  591.                           if(fi->xfi_Comment && !args.nocomment)
  592.                             SetComment(filename, fi->xfi_Comment);
  593.                           /* SetOwner ??? */
  594.                         }
  595.                   }
  596.                 } 
  597.                 else
  598.                 {
  599.                   struct DateStamp d;
  600.  
  601.               if(namesize)
  602.                 xh.finish = CheckNameSize(FilePart(filename), namesize);
  603.  
  604.               if(!xh.finish)
  605.               {
  606.                 LONG e;
  607.  
  608.                 ++numfile;
  609.  
  610.                 if(args.diskimage || args.diskarchive)
  611.                       e = xadDiskFileUnArc(ai, XAD_OUTFILENAME, filename,
  612.                           XAD_ENTRYNUMBER, fi->xfi_EntryNumber, XAD_MAKEDIRECTORY,
  613.                           !args.askmakedir, XAD_OVERWRITE, args.overwrite,
  614.                           XAD_NOKILLPARTIAL, args.nokillpart,  args.quiet ? TAG_IGNORE :
  615.                           XAD_PROGRESSHOOK, &prhook, TAG_DONE);
  616.                     else
  617.                       e = xadFileUnArc(ai, XAD_OUTFILENAME, filename,
  618.                           XAD_ENTRYNUMBER, fi->xfi_EntryNumber, XAD_MAKEDIRECTORY,
  619.                           !args.askmakedir, XAD_OVERWRITE, args.overwrite,
  620.                           XAD_NOKILLPARTIAL, args.nokillpart,  args.quiet ? TAG_IGNORE :
  621.                           XAD_PROGRESSHOOK, &prhook, TAG_DONE);
  622.  
  623.                         if(!e)
  624.                         {
  625.                           if(!args.nodate && !(fi->xfi_Flags & XADFIF_NODATE)
  626.                           && !xadConvertDates(XAD_DATEXADDATE, &fi->xfi_Date,
  627.                           XAD_GETDATEDATESTAMP, &d, TAG_DONE))
  628.                             SetFileDate(filename, &d);
  629.                           if(!args.noprot)
  630.                             SetProtection(filename, fi->xfi_Protection);
  631.                           if(fi->xfi_Comment && !args.nocomment)
  632.                             SetComment(filename, fi->xfi_Comment);
  633.                           /* SetOwner ??? */
  634.                         }
  635.                         else
  636.                           ++numerr;
  637.                       }
  638.                     }
  639.                   }
  640.                   fi = fi->xfi_Next;
  641.                 }
  642.               }
  643.             }
  644.             ti2[2].ti_Tag = XAD_STARTCLIENT;
  645.             ti2[2].ti_Data = (ULONG) ai->xai_Client->xc_Next;
  646.             xadFreeInfo(ai);
  647.             if(--loop)
  648.             {
  649.               loop = 0;
  650.               if(ti2[2].ti_Data)
  651.               {
  652.             xadFreeObjectA(ai, 0); /* realloc ai structure */
  653.                 if((ai = (struct xadArchiveInfo *) xadAllocObjectA(XADOBJ_ARCHIVEINFO, 0)))
  654.                 {
  655.                   if(!xadGetDiskInfoA(ai, ti2))
  656.                     loop = 2;
  657.                 }
  658.               }
  659.             }
  660.         if(!args.info && !loop && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
  661.         {
  662.           Printf("Processed");
  663.           if(numfile)
  664.             Printf(" %ld file%s%s", numfile, numfile == 1 ? "" : "s", numdir ? " and" : "");
  665.           if(numdir)
  666.             Printf(" %ld director%s", numdir, numdir == 1 ? "y" : "ies");
  667.           if(!numfile && !numdir)
  668.             Printf(" nothing");
  669.           if(numerr)
  670.             Printf(", %ld error%s", numerr, numerr == 1 ? "" : "s");
  671.           Printf(".\n");
  672.         }
  673.           } /* xadGetInfo, loop */
  674.  
  675.           if(ai)
  676.             xadFreeObjectA(ai, 0);
  677.             } /* xadAllocObject */
  678.           }
  679.           else
  680.             SetIoErr(ERROR_REQUIRED_ARG_MISSING);
  681.  
  682. #ifdef MULTIFILE
  683.       if(argstring)
  684.         FreeVec(argstring);
  685. #endif
  686.  
  687.           FreeArgs(rda);
  688.         } /* ReadArgs */
  689.         FreeDosObject(DOS_RDARGS, rda);
  690.       } /* AllocDosObject */
  691.  
  692.       if(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
  693.         SetIoErr(ERROR_BREAK);
  694.  
  695.       if(!args.quiet)
  696.       {
  697.         if(err)
  698.       Printf("An error occured: %s\n", xadGetErrorText(err));
  699.         else if(ret)
  700.           PrintFault(IoErr(), 0);
  701.       }
  702.  
  703.       CloseLibrary((struct Library *) xadmasterbase);
  704.     } /* OpenLibrary xadmaster */
  705.     else
  706.       Printf("Could not open xadmaster.library\n");
  707.     CloseLibrary((struct Library *) dosbase);
  708.   } /* OpenLibrary dos */
  709.   return ret;
  710. }
  711.  
  712. /* Because of SAS-err, this cannot be SAVEDS */
  713. ASM(ULONG) progrhook(REG(a0, struct Hook *hook),
  714. REG(a1, struct xadProgressInfo *pi))
  715. {
  716.   ULONG ret = 0;
  717.   STRPTR name = ((struct xHookArgs *) (hook->h_Data))->name;
  718.  
  719.   switch(pi->xpi_Mode)
  720.   {
  721.   case XADPMODE_ASK:
  722.     ret |= ((struct xHookArgs *) (hook->h_Data))->flags;
  723.     if((pi->xpi_Status & XADPIF_OVERWRITE) && !(ret & XADPIF_OVERWRITE))
  724.     {
  725.       LONG r;
  726.  
  727.       Printf("File '%s' already exists, overwrite? (Y|A|S|\033[1mN\033[0m|Q|R): ",
  728.       pi->xpi_FileName);
  729.       Flush(Output());
  730.       SetMode(Input(), TRUE);
  731.       r = FGetC(Input());
  732.       SetMode(Input(), FALSE);
  733.       switch(r)
  734.       {
  735.       case 'a': case 'A':
  736.     ((struct xHookArgs *) (hook->h_Data))->flags |= XADPIF_OVERWRITE;
  737.       case 'y': case 'Y': ret |= XADPIF_OVERWRITE; break;
  738.       case 's': case 'S': ret |= XADPIF_SKIP; break;
  739.       case 'q': case 'Q': ((struct xHookArgs *) (hook->h_Data))->finish = 1; break;
  740.       case 'r': case 'R':
  741.         Printf("\r\033[KEnter new (full) name for '%s':", pi->xpi_FileName);
  742.         Flush(Output());
  743.         FGets(Input(), name, NAMEBUFSIZE-1); /* 1 byte less to correct bug before V39 */
  744.         r = strlen(name);
  745.         if(name[r-1] == '\n') /* skip return character */
  746.           name[--r] = 0;
  747.         Printf("\033[1F\033[K"); /* go up one line and clear it */
  748.         if((pi->xpi_NewName = xadAllocVec(++r, MEMF_PUBLIC)))
  749.         {
  750.           while(r--)
  751.             pi->xpi_NewName[r] = name[r];
  752.           ret |= XADPIF_RENAME;
  753.         }
  754.         else
  755.           Printf("No memory to store new name\n");
  756.       }
  757.     }
  758.     if((pi->xpi_Status & XADPIF_MAKEDIRECTORY) &&
  759.     !(ret & XADPIF_MAKEDIRECTORY))
  760.     {
  761.       Printf("Directory of file '%s' does not exist, create? (Y|A|S|\033[1mN\033[0m|Q): ",
  762.       name);
  763.       Flush(Output());
  764.       SetMode(Input(), TRUE);
  765.       switch(FGetC(Input()))
  766.       {
  767.       case 'a': case 'A':
  768.     ((struct xHookArgs *) (hook->h_Data))->flags |= XADPIF_MAKEDIRECTORY;
  769.       case 'y': case 'Y': ret |= XADPIF_MAKEDIRECTORY; break;
  770.       case 's': case 'S': ret |= XADPIF_SKIP; break;
  771.       case 'q': case 'Q': ((struct xHookArgs *) (hook->h_Data))->finish = 1;
  772.       }
  773.       SetMode(Input(), FALSE);
  774.     }
  775.     break;
  776.   case XADPMODE_PROGRESS:
  777.     if(pi->xpi_CurrentSize - ((struct xHookArgs *) (hook->h_Data))->lastprint >= MINPRINTSIZE)
  778.     {
  779.       if(pi->xpi_FileInfo->xfi_Flags & XADFIF_NOUNCRUNCHSIZE)
  780.         Printf("\r\033[KWrote %8ld bytes: %s", pi->xpi_CurrentSize, name);
  781.       else
  782.         Printf("\r\033[KWrote %8ld of %8ld bytes: %s",
  783.         pi->xpi_CurrentSize, pi->xpi_FileInfo->xfi_Size, name);
  784.       Flush(Output());
  785.       ((struct xHookArgs *) (hook->h_Data))->lastprint = pi->xpi_CurrentSize;
  786.     }
  787.     break;
  788.   case XADPMODE_END: Printf("\r\033[KWrote %8ld bytes: %s\n",
  789.     pi->xpi_CurrentSize, name);
  790.     break;
  791.   case XADPMODE_ERROR: Printf("\r\033[K%s: %s\n", name,
  792.     xadGetErrorText(pi->xpi_Error));
  793.     break;
  794.   }
  795.  
  796.   if(!(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)) /* clear ok flag */
  797.     ret |= XADPIF_OK;
  798.  
  799.   return ret;
  800. }
  801.  
  802. void ShowProt(ULONG i)
  803. {
  804.   LONG j;
  805.   UBYTE buf[16], *b = "rwedrwedhsparwed";
  806.   
  807.   for(j = 0; j <= 11; ++j)
  808.     buf[j] = (i & (1<<(15-j))) ? b[j] : '-';
  809.   for(; j <= 15; ++j)
  810.     buf[j] = (i & (1<<(15-j))) ? '-' : b[j];
  811.  
  812.   Printf("%.16s ", buf);
  813. }
  814.  
  815. LONG CheckNameSize(STRPTR name, ULONG size)
  816. {
  817.   LONG ret = 0;
  818.   LONG r;
  819.  
  820.   if((r = strlen(name)) > size)
  821.   {
  822.     UBYTE buf[NAMEBUFSIZE];
  823.  
  824.     Printf("\r\033[KFilename '%s' exceeds name limit of %ld by %ld, rename? (Y|\033[1mN\033[0m|Q): ", name, size, r-size);
  825.  
  826.     Flush(Output());
  827.     SetMode(Input(), TRUE);
  828.     r = FGetC(Input());
  829.     SetMode(Input(), FALSE);
  830.     switch(r)
  831.     {
  832.     case 'q': case 'Q': ret = 1; break;
  833.     case 'y': case 'Y':
  834.       Printf("\r\033[KEnter new name for '%s':", name);
  835.       Flush(Output());
  836.       FGets(Input(), buf, NAMEBUFSIZE-1); /* 1 byte less to correct bug before V39 */
  837.       r = strlen(buf);
  838.       if(buf[r-1] == '\n') /* skip return character */
  839.         buf[--r] = 0;
  840.       Printf("\033[1F\033[K"); /* go up one line and clear it */
  841.       if(!(ret = CheckNameSize(buf, size)))
  842.       {
  843.         for(r = 0; buf[r]; ++r)
  844.           *(name++) = buf[r];
  845.         *name = 0;
  846.       }
  847.       break;
  848.     }
  849.   }
  850.   return ret;
  851. }
  852.  
  853. void CalcPercent(ULONG cr, ULONG ucr, ULONG *p1, ULONG *p2)
  854. {
  855.   ULONG i = 0, j = 0;
  856.  
  857.   if(cr < ucr)
  858.   {
  859.     if(cr > (0xFFFFFFFF/1000))
  860.       i = 1000 - cr / (ucr / 1000);
  861.     else
  862.       i = 1000 - (1000 * cr) / ucr;
  863.     j = i % 10;
  864.     i /= 10;
  865.   }
  866.   *p1 = i;
  867.   *p2 = j;
  868. }
  869.  
  870. #ifndef MULTIFILE
  871. /* would be better to store the pattern parse stuff and do it only once,
  872. but so it is a lot easier */
  873. LONG CheckName(STRPTR *pat, STRPTR name)
  874. {
  875.   UBYTE buf[PATBUFSIZE];
  876.   while(*pat)
  877.   {
  878.     if(ParsePatternNoCase(*(pat++), buf, PATBUFSIZE) >= 0)
  879.     {
  880.       if(MatchPatternNoCase(buf, name))
  881.         return 1;
  882.     } /* A scan failure means no recognition, should be an error print here */
  883.   }
  884.   return 0;
  885. }
  886. #else
  887. STRPTR *GetNames(STRPTR *names)
  888. {
  889.   struct AnchorPath *APath;
  890.   STRPTR *result = 0, s, f, *r;
  891.   ULONG *filelist, *fl = 0, *a, *b, retval = 0, namesize = 0;
  892.   LONG i;
  893.  
  894.   if((APath = (struct AnchorPath *) AllocMem(sizeof(struct AnchorPath)+512, MEMF_PUBLIC|MEMF_CLEAR)))
  895.   {
  896.     APath->ap_BreakBits = SIGBREAKF_CTRL_C;
  897.     APath->ap_Strlen = 512;
  898.  
  899.     while(*names && !retval)
  900.     {
  901.       filelist = 0;
  902.       for(retval = MatchFirst(*names, APath); !retval; retval = MatchNext(APath))
  903.       {
  904.         if(APath->ap_Info.fib_DirEntryType < 0)
  905.         {
  906.           i = strlen(APath->ap_Buf)+1;
  907.           if(!(a = (ULONG *) AllocVec(i+4, MEMF_ANY)))
  908.             break;
  909.           CopyMem(APath->ap_Buf, a+1, i);
  910.           namesize += i;
  911.           if(!filelist)
  912.           {
  913.             filelist = a; *a = 0;
  914.           }
  915.           else if(stricmp((STRPTR) (filelist+1), APath->ap_Buf) >= 0)
  916.           {
  917.             *a = (ULONG) filelist; filelist = a;
  918.           }
  919.           else
  920.           {
  921.             for(b = filelist; *b && (i = SDI_stricmp((STRPTR) (*b+4),
  922.             APath->ap_Buf)) < 0; b = (ULONG *) *b)
  923.               ;
  924.             *a = *b; *b = (ULONG) a;
  925.           }
  926.         }
  927.       }
  928.       if(fl)
  929.       {
  930.         for(b = fl; *b; b = (ULONG *) *b)
  931.           ;
  932.         *b = (ULONG) filelist;
  933.       }
  934.       else
  935.         fl = filelist;
  936.       MatchEnd(APath);
  937.       if(retval == ERROR_NO_MORE_ENTRIES)
  938.         retval = 0;
  939.       ++names;
  940.     }
  941.  
  942.     if(!retval)
  943.     {
  944.       i = 0;
  945.       for(b = fl; b; b = (ULONG *) *b)
  946.         ++i;
  947.       if((result = (STRPTR *)AllocVec((i+1)*sizeof(STRPTR)+namesize, MEMF_ANY)))
  948.       {
  949.         s = ((STRPTR) result)+((i+1)*sizeof(STRPTR));
  950.         i = 0;
  951.         for(b = fl; b; b = (ULONG *) *b)
  952.         {
  953.           result[i++] = s;
  954.           for(f = (STRPTR) (b+1); *f; ++f)
  955.             *(s++) = *f;
  956.           *(s++) = 0;
  957.         }
  958.         result[i] = 0;
  959.       }
  960.     }
  961.  
  962.     while(fl)
  963.     {
  964.       a = (ULONG *) *fl;
  965.       FreeVec(fl);
  966.       fl = a;
  967.     }
  968.  
  969.     FreeMem(APath, sizeof(struct AnchorPath)+512);
  970.   }
  971.  
  972.   if(!retval)
  973.   {
  974.     Printf("Loading files in following order: ");
  975.  
  976.     for(r = result; *r; ++r)
  977.       Printf("%s%s", *r, r[1] ? ", " : "\n");
  978.   }
  979.  
  980.   return result;
  981. }
  982. #endif
  983.